// 代码源自：https://segmentfault.com/a/1190000043972287
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <hs/hs.h>

// 枚举类型，方便后续使用
enum {
    HYPERSCAN_ID_NONE = 0,
    HYPERSCAN_ID_TEST1,
    HYPERSCAN_ID_TEST2,
    HYPERSCAN_ID_MAX
};

// 编译数据结构
typedef struct CompilePattern {
    uint32_t ids;
    const char *exps;
} CompilePattern_t;

// 编译到数据库中的匹配字段，
// hyperscan编译阶段有一个特殊字符转义的过程
static const CompilePattern_t gCompilePattern[] = {
        {HYPERSCAN_ID_NONE,  " "},
        {HYPERSCAN_ID_TEST1, "123.{1,3}abc"},
        {HYPERSCAN_ID_TEST2, "max"}
};

// 将数据库中待编译的信息保存到这个数组里面
typedef struct CompilePatternArray {
    uint32_t ids[20];
    uint32_t flag[20];
    const char *exps[20];
} CompilePatternArray_t;

static int CompilePatterns(CompilePattern_t *CompPatt, uint32_t count, hs_database_t **pDatabase) {
    hs_error_t error;
    hs_compile_error_t *ComError;
    CompilePatternArray_t compilePattern;

    // 一对一存储，转存
    int i;
    for (i = 0; i < count; i++) {
        compilePattern.ids[i] = CompPatt[i].ids;
        compilePattern.exps[i] = CompPatt[i].exps;
        compilePattern.flag[i] = HS_FLAG_SOM_LEFTMOST | HS_FLAG_CASELESS;
    }

    // 编译
    error = hs_compile_multi(compilePattern.exps, compilePattern.flag,
                             compilePattern.ids, count, HS_MODE_BLOCK, NULL,
                             pDatabase,
                             (hs_compile_error_t **) &ComError);
    if (error != HS_SUCCESS) {
        // 失败的话给出相应的提示信息
        printf("compile failed, error code is %d\n", error);
        fprintf(stderr, "ERROR: %s\n", ComError->message);
    }

    return 0;
}

// hyperscan 回调函数
static int onMatch(unsigned int id,
                   unsigned long long from, unsigned long long to,
                   unsigned int flags, void *ctx)
{

    char *tmp = (char *) ctx;

    unsigned long long len = to - from;

    printf("id is %d\n", id);
    printf("from=%lld, to=%lld\n", from, to);
    switch (id) {
        case HYPERSCAN_ID_NONE:
            printf("\n");
            break;
        case HYPERSCAN_ID_TEST1:
            printf("%.*s\n", (int)len, tmp + from);
            break;
        case HYPERSCAN_ID_TEST2:
            printf("%.*s\n", (int)len, tmp + from);
            break;
        default:
            printf("can not found any subString");
            break;
    }

    return 0;
}

int main(int argc, char **argv)
{
    hs_database_t *HsDatabase = NULL;
    // 临时空间指针需要初始化为NULL
    hs_scratch_t *HsStra = NULL;
    CompilePattern_t *CompPatt = (CompilePattern_t *) gCompilePattern;

    int count = 0;

    // 计算规则数量。
    count = sizeof(gCompilePattern) / sizeof(CompilePattern_t);

    char tmpString[] = {"abc123123123abcmax123123bacbacabc\0"};

    // 编译
    CompilePatterns(CompPatt, count, (hs_database_t **) &HsDatabase);

    // 申请scratch 空间
    hs_alloc_scratch(HsDatabase, (hs_scratch_t **) &HsStra);

    hs_scan(HsDatabase, tmpString, strlen(tmpString), 0, HsStra, onMatch, tmpString);

    // 释放空间
    hs_free_database(HsDatabase);
    hs_free_scratch(HsStra);
    return 0;
}
